package cn.cj.erp.bo.system;

import cn.cj.erp.common.SearchParam;
import cn.cj.erp.common.annotation.Search;
import cn.cj.erp.common.enums.SearchType;
import cn.cj.erp.common.enums.SexEnum;
import cn.cj.erp.common.enums.StatusEnum;
import cn.cj.erp.common.enums.UserTypeEnum;
import cn.cj.erp.common.excel.anno.Excel;
import cn.cj.erp.common.excel.enums.ExcelType;
import cn.cj.erp.common.utils.encrypt.AesUtil;
import cn.cj.erp.common.utils.encrypt.EncryptUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import lombok.EqualsAndHashCode;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.Date;
import java.util.List;

/**
 * 系统用户
 *
 * @author chenjian
 */
@Data
@EqualsAndHashCode(callSuper = true)
public class SysUserBo extends SearchParam {

    /** 用户ID */
    @JsonSerialize(using = ToStringSerializer.class)
    private Long userId;

    /** 部门ID */
    @Excel(name = "部门编号", sort = 0)
    @NotNull(message = "部门不能为空")
    @JsonSerialize(using = ToStringSerializer.class)
    private Long deptId;

    /** 部门ids，仅用于搜索 */
    @Search(type = SearchType.IN, fieldName = "dept_id")
    private List<Long> deptIds;

    /** 用户名 */
    @Excel(name = "登录名")
    @NotBlank(message = "用户名不能为空")
    @Search(type = SearchType.LIKE)
    private String username;

    /** 姓名(加密) */
    @Excel(name = "姓名")
    @NotBlank(message = "姓名不能为空")
    private String name;

    /** 姓名搜索，用于辅助name模糊搜索用，必须按照约定，建议增加Search的后缀 */
    @Search(type = SearchType.LIKE)
    private String nameSearch;

    /** 密码 */
    private String password;

    /** 手机(加密) */
    @Excel(name = "手机")
    @Search(type = SearchType.EQ)
    private String phone;

    /** 邮箱(加密) */
    @Excel(name = "邮箱")
    @Search(type = SearchType.EQ)
    private String email;

    /** 用户性别 */
    @Excel(name = "性别", combo = {"男", "女", "未知"})
    private SexEnum sex;

    /** 头像地址 */
    private String avatar;

    /** 前后台类型标识 0:后台用户 1:前台用户 */
    private UserTypeEnum userType;

    /** 状态 */
    @Excel(name = "帐号状态", combo = {"正常", "异常"})
    @Search(type = SearchType.EQ)
    private StatusEnum status;

    /** 最后修改密码时间 */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date lastPassTime;

    /** 最后登录IP */
    @Excel(name = "最后登录IP", type = ExcelType.EXPORT)
    private String loginIp;

    /** 最后登录时间 */
    @Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = ExcelType.EXPORT)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date loginTime;

    /** 创建时间 */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date createTime;

    /** 更新时间 */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date modifyTime;

    /** 更新时间开始，仅搜索 */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @Search(type = SearchType.BETWEEN_BEGIN, fieldName = "modify_time")
    private Date beginTime;

    /** 更新时间结束，仅搜索 */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @Search(type = SearchType.BETWEEN_END, fieldName = "modify_time")
    private Date endTime;

    /** 部门名称 */
    @Excel(name = "部门名称", sort = 1)
    private String deptName;

    /** 角色对象 */
    private List<SysRoleBo> roles;

    /** 角色组 */
    private List<Long> roleIds;

    /** 角色ID */
    @Search(type = SearchType.APPLY, apply = " user_id IN (SELECT user_id FROM sys_user_role WHERE role_id = {})")
    private Long roleId;

    /** uuid(前端上传用户名和密码加密，该字段用于解密) */
    private String uuid;

    /**
     * 解密密码，前端上传，服务端解密
     */
    public void decryptPasswordFromClient() {
        if (StrUtil.isEmpty(this.password)) {
            return;
        }
        this.password = AesUtil.decrypt(StrUtil.replace(this.password, " ", "+"),
                this.uuid.substring(16));
    }

    /**
     * 对敏感字段加密
     */
    public void encrypt() {
        this.setName(EncryptUtil.encrypt(this.getName()));
        this.setNameSearch(EncryptUtil.searchEncrypt(this.getName()));
        this.setPhone(EncryptUtil.encrypt(this.getPhone()));
        this.setEmail(EncryptUtil.encrypt(this.getEmail()));
        if (StrUtil.isNotBlank(this.getPassword())) {
            this.setPassword(EncryptUtil.passwordEncrypt(this.getPassword()));
        }
    }

    /**
     * 对敏感字段解密
     */
    public void decrypt() {
        this.setName(EncryptUtil.decrypt(this.getName()));
        this.setPhone(EncryptUtil.decrypt(this.getPhone()));
        this.setEmail(EncryptUtil.decrypt(this.getEmail()));
    }

    /**
     * 对敏感字段脱敏
     */
    public void hide() {
        this.setPassword(null);
        this.setNameSearch(null);
    }
}
